package com.tanhua.app.service;

import cn.hutool.core.collection.CollUtil;
import com.tanhua.api.MovementApi;
import com.tanhua.api.UserInfoApi;
import com.tanhua.api.VisitorsApi;
import com.tanhua.app.exception.BusinessException;
import com.tanhua.app.exception.ErrorResult;
import com.tanhua.app.interceptor.UserHolder;
import com.tanhua.commons.utils.Constants;
import com.tanhua.config.template.OssTemplate;
import com.tanhua.model.enums.CommentType;
import com.tanhua.model.mongo.Movement;
import com.tanhua.model.mongo.Visitors;
import com.tanhua.model.pojo.UserInfo;
import com.tanhua.model.vo.MovementsVo;
import com.tanhua.model.vo.PageResult;
import com.tanhua.model.vo.VisitorsVo;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.sound.midi.VoiceStatus;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class MovementService {

    @Autowired
    private MqMessageService mqMessageService;

    @Autowired
    private OssTemplate ossTemplate;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @DubboReference
    private MovementApi movementApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private VisitorsApi visitorsApi;

    //发布动态
    public void publishMovement(Movement movement, MultipartFile[] imageContent) throws IOException {
        //1 判断文字动态是否为空，如果为空，抛异常
        if (StringUtils.isBlank(movement.getTextContent())) {
            throw new BusinessException(ErrorResult.contentError());
        }

        //2 上传动态图片到阿里云OSS
        List<String> medias = new ArrayList<>();
        for (MultipartFile multipartFile : imageContent) {
            String picUrl = ossTemplate.uploadOss(multipartFile.getInputStream(), multipartFile.getOriginalFilename());
            medias.add(picUrl);
        }

        //3 调用API实现动态发布
        movement.setMedias(medias);//动态图片
        movement.setUserId(UserHolder.getUserId());//发布动态的用户id
        movement.setCreated(System.currentTimeMillis());

        String movementId = movementApi.publish(movement);

        //发送动态审核的消息
        mqMessageService.sendAudiMessage(movementId);

        //发送动态操作日志消息
        mqMessageService.sendLogMessage(UserHolder.getUserId(), "0201", "movement", movementId);
    }

    public PageResult<MovementsVo> findByUserId(Long userId, Integer page, Integer pagesize) {
        //1 根据用户id分页查询动态数据
        PageResult pageResult = movementApi.findByUserId(userId, page, pagesize);

        //2 判读动态集合是否为空，如果为空直接返回
        //if (movementList == null || movementList.isEmpty()) {
        if (CollUtil.isEmpty(pageResult.getItems())) {
            return pageResult;
        }

        //3 根据用户id查询用户详情
        UserInfo userInfo = userInfoApi.findById(userId);

        //4 封装vos
        List<Movement> movementList = pageResult.getItems();
        List<MovementsVo> vos = new ArrayList<>();
        for (Movement movement : movementList) {
            MovementsVo vo = MovementsVo.init(userInfo, movement);
            vos.add(vo);
        }

        //5 封装分页对象返回数据
        return new PageResult<>(page, pagesize, pageResult.getCounts(), vos);
    }

    //分页查询好友动态  不返回查询总记录数
    public PageResult<MovementsVo> findFriendMovements(Integer page, Integer pagesize) {
        //1 分页查询好友动态
        List<Movement> movementList = movementApi.findFriendMovements(UserHolder.getUserId(), page, pagesize);

        return getPageResult(page, pagesize, movementList);
    }

    //通用的封装分页对象的方法
    private PageResult<MovementsVo> getPageResult(Integer page, Integer pagesize, List<Movement> movementList) {
        //2 判断好友动态是否为空，为空直接返回
        if (CollUtil.isEmpty(movementList)) {
            return new PageResult<>(page, pagesize, 0, null);
        }

        //3 获取所有动态的 用户ids
        List<Long> ids = movementList.stream()
                .map(Movement::getUserId).collect(Collectors.toList());

        //4 根据动态发布人的ids 查询用户详情  UserInfo
        List<UserInfo> userInfoList = userInfoApi.findByIds(ids);
        //把list转map
        Map<Long, UserInfo> map = userInfoList.stream()
                .collect(Collectors.toMap(UserInfo::getId, Function.identity()));

        //5 封装返回的vos
        List<MovementsVo> vos = new ArrayList<>();
        for (Movement movement : movementList) {
            UserInfo userInfo = map.get(movement.getUserId());
            if (userInfo != null) {
                MovementsVo vo = MovementsVo.init(userInfo, movement);


                //让点赞可以正常回显
                String key = Constants.MOVEMENTS_INTERACT_KEY + movement.getId().toHexString();
                String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
                if (redisTemplate.opsForHash().hasKey(key, hashKey)) {
                    //如果redis有点赞数据，说明已经点赞过了，设置为1，才能回显出效果
                    vo.setHasLiked(1);
                } else {
                    vo.setHasLiked(0);
                }


                //让喜欢可以正常回显
                String loveKey = Constants.MOVEMENTS_INTERACT_KEY + movement.getId().toHexString();
                String loveHashKey = Constants.MOVEMENT_LOVE_HASHKEY + UserHolder.getUserId();
                if (redisTemplate.opsForHash().hasKey(loveKey, loveHashKey)) {
                    //如果redis有喜欢数据，说明已经喜欢过了，设置为1，才能回显出效果
                    vo.setHasLoved(1);
                } else {
                    vo.setHasLoved(0);
                }


                vos.add(vo);
            }
        }

        //6 封装返回分页对象
        return new PageResult<>(page, pagesize, 0, vos);
    }

    //查询推荐动态列表
    public PageResult findRecommendMovements(Integer page, Integer pagesize) {
        //1 查询redis中的推荐数据
        String value = redisTemplate.opsForValue().get(Constants.MOVEMENTS_RECOMMEND + UserHolder.getUserId());

        //2 判断是否存在推荐数据
        //声明存放动态的容器
        List<Movement> movementList = new ArrayList<>();
        if (StringUtils.isBlank(value)) {
            //2.1 如果不存在推荐动态数据，随机获取10条动态
            movementList = movementApi.randomMovement(pagesize);
        } else {
            //2.2 如果存在推荐动态数据，对数据进行分页
            String[] pidArr = value.split(",");
            //判断当前页是否有数据    动态数据 10条      每页4条      1：4  2：4   3：2  4：0（第4页不查询）
            if (pidArr.length > (page - 1) * pagesize) {
                //对数据进行分页
                List<Long> pids = Arrays.stream(pidArr)
                        .skip((page - 1) * pagesize)  //设置分页  跳过哪些数据
                        .limit(pagesize)              //设置分页  每页显示多少条数据
                        .map(pid -> Long.parseLong(pid)) //把pid由String转为Long
                        .collect(Collectors.toList());   //输出的是List集合

                //根据pid查询动态数据
                movementList = movementApi.findByPids(pids);
            }
        }

        ////3 查询动态发布者的用户详情
        //List<Long> ids = movementList.stream()
        //        .map(Movement::getUserId).collect(Collectors.toList());
        ////List<UserInfo> list = userInfoApi.findByIds(ids);
        ////Map<Long, UserInfo> map = list.stream().collect(Collectors.toMap(UserInfo::getId, Function.identity()));
        //Map<Long, UserInfo> map = userInfoApi.findByIds(ids).stream()
        //        .collect(Collectors.toMap(UserInfo::getId, Function.identity()));
        //
        ////4 封装vos
        //List<MovementsVo> vos = new ArrayList<>();
        //for (Movement movement : movementList) {
        //    UserInfo userInfo = map.get(movement.getUserId());
        //    if (userInfo != null) {
        //        MovementsVo vo = MovementsVo.init(userInfo, movement);
        //        vos.add(vo);
        //    }
        //}
        //
        ////5 封装返回的分页对象
        //return new PageResult(page, pagesize, 0, vos);

        return getPageResult(page, pagesize, movementList);
    }

    public MovementsVo findById(String movementId) {
        //1 查询动态
        Movement movement = movementApi.findById(movementId);

        //2 判断好友动态是否为空，为空直接返回
        if (movement == null) {
            return null;
        }

        //3 获取动态用户id
        Long userId = movement.getUserId();

        //4 根据动态发布人的id 查询用户详情
        UserInfo userInfo = userInfoApi.findById(userId);

        //5 封装返回的vo
        MovementsVo vo = MovementsVo.init(userInfo, movement);

        //发日志消息
        mqMessageService.sendLogMessage(userId, "0202", "movement", movement.getId().toHexString());

        //6 返回vo对象
        return vo;
    }

    //谁看过我  访客信息查询
    public List<VisitorsVo> queryVisitorsList() {
        //1 获取redis中存放的上一次查询访客时间
        String key = Constants.VISITORS_USER;
        String hashKey = UserHolder.getUserId().toString();
        String value = (String) redisTemplate.opsForHash().get(key, hashKey);
        Long date = value == null ? null : Long.parseLong(value);//解析redis中存放的时间

        //2 调用api查询访客数据
        List<Visitors> visitorsList = visitorsApi.queryVisitorsList(UserHolder.getUserId(), date);

        //3 判断是否有数据，如果为空，直接返回
        if (CollUtil.isEmpty(visitorsList)) {
            return null;
        }

        //4 根据访客的ids查询访客的用户详情
        //List<Long> ids = CollUtil.getFieldValues(visitorsList, "visitorUserId", Long.class);
        List<Long> ids = visitorsList.stream().map(Visitors::getVisitorUserId).collect(Collectors.toList());
        Map<Long, UserInfo> map = userInfoApi.findByIds(ids).stream()
                .collect(Collectors.toMap(UserInfo::getId, Function.identity()));

        //5 封装vos
        List<VisitorsVo> vos = new ArrayList<>();
        for (Visitors visitors : visitorsList) {
            UserInfo userInfo = map.get(visitors.getVisitorUserId());
            if (userInfo != null) {
                VisitorsVo vo = VisitorsVo.init(userInfo, visitors);
                vos.add(vo);
            }
        }

        //6 返回结果
        return vos;
    }
}
